#include "../chance.hpp"
#include <vector>
#include <iostream>
#include <time.h>

using namespace std;
using namespace gen;

INITIALIZE_GENERATOR

/// Memory object

struct data {
	string name;
	string type;
};

struct table {
	string name;
	vector<data> attributs;
	vector<string> values;
};

/// getter

struct data_range : range< vector<data>::const_iterator > {	
	data_range(table const& me)
	: self_t(me.attributs.begin(), me.attributs.end())
	{}
};

struct table_range : range< vector<table>::const_iterator > {	
	table_range(vector<table> const& me)
	: self_t(me.begin(), me.end())
	{}
};

struct value_range : range< vector<string>::const_iterator > {	
	value_range(table const& me)
	: self_t(me.values.begin(), me.values.end())
	{}
};

struct NameFormatter {
	const char * operator()(vector<table>::const_iterator ite) const
	{
		return ite->name.c_str();
	}	
};

struct DataFormatter {
	const char * operator()(vector<data>::const_iterator ite) const
	{
		return ite->name.c_str();
	}
};

struct TypeFormatter {
	template <class ContextT>
	const char * operator()(const ContextT & c) const
	{
		typename at_t<ContextT,2>::type myContext = c.template at<2>();
		return c.template at<2>().current()->type.c_str();
	}
};

struct ConditionalBranching {
	bool operator()(vector<table>::const_iterator ite) const
	{
		return false;
	}
};

struct ConditionalName {
	template <class ContextT>
	bool operator()(ContextT c) const
	{
		cout << "ent :   " << c.current()->name << endl;
		return c.current() != (c.domain().last()-1);
	}
};

/// My SQL Format file
struct MySQLGenerator : public report<MySQLGenerator> {

	template <typename InfoT>
	struct etat {
		NameFormatter NameFormat;
		DataFormatter DataFormat;
		TypeFormatter TypeFormat;
		ConditionalBranching IsComment;
		ConditionalName IsName;

		//typedef limit<InfoT,data_range>			data_limit;
		typedef limit_n<InfoT,1>				table_limit;
		typedef typename table_limit::context_t	table_context;

		typedef limit_n<table_context,2>		data_limit;
		typedef typename data_limit::context_t	data_context;

		typedef limit<table_context,value_range>	value_limit;
		typedef typename value_limit::context_t		value_context;

		format<InfoT>		ScriptSQL;
		format<table_context>	CreateTable, CreateRecursif, CreateComment, Smiley;
		format<data_context>	CreateAttribut;
		format<value_context>	CreateValue;
		condition<table_context> If_IsComment, If_ExistValue;

		varstr<> CreateSub;

		etat(MySQLGenerator const& me) 
		{
            data_limit data0(data_limit::beg);
			data_limit dataN(data_limit::end);

            value_limit value0(value_limit::beg);
			value_limit valueN(value_limit::end);

            table_limit table0(table_limit::beg);
			table_limit tableN(table_limit::end);

            If_IsComment = (false || !if_g(IsComment)) && true;
			If_ExistValue = nbOfValid_g(0,value0,valueN,gt_g(),cst_expr(true));

			ScriptSQL = 
				( (CreateTable << '\n' << '\n') 
				<< CreateRecursif << '\n')							[table0, tableN];//[table0+1];//
			
			Smiley =
				str_g("-_-") << $(0) << " value : '" << $(1)[value0] ;

			CreateTable = 
				str_g("CREATE TABLE ") << act_g(NameFormat) << '('
					<< ( '\t' << CreateAttribut << ",\n\t\t" )		[data0, dataN-1]
					<< ( '\t' << CreateAttribut )					[dataN-1]//, dataN]
					<< ( ch_g('\t') << CreateComment(Smiley, index_g()) )		[If_IsComment] 
					<< ( '\t' << CreateValue << "\n" )				[value0, valueN][If_ExistValue] 
					<< CreateSub(str_g("pRint"), str_g("\t cout << \"hello\" << endl; "))
				<< ");\n\n";

			CreateComment =
				str_g("-- un commentaire ") << /*-str_g("-> ") <<*/ Smiley(str_g(" -> ") << $(1), CreateValue << "'") << " " << $(1) << "\n";

			CreateAttribut = 
				act3_g<2>(DataFormat) << ' ' << act2_g(TypeFormat) ;

			CreateValue =
				str_g("# ") << value_g() ;

			CreateRecursif =
				(str_g("{") << act_g(NameFormat) << "(" << index_g()+1 << -str_g("[-]") << ")" << "," << *CreateRecursif << "}")	[if2_g(IsName)]
				<< (str_g("{") << act3_g<1>(NameFormat) << "(" << index_g()+1 << ")" << "}")										[!if2_g(IsName)]
				;

			CreateSub = "void $U[0,1] L[1] 0$() { $1$ }\n"; 
		}

		format<InfoT> const& start() const { return ScriptSQL; }
    };
};

/// test program

int main(){
	{
	vector<table> database;
	table person, company;
	data tel, address;

	person.name = "personne";
	tel.name = "telephone";
	tel.type = "string";
	address.name = "adresse";
	address.type = "text";
	person.attributs.push_back(tel);
	person.attributs.push_back(address);
	person.values.push_back("val1");
	person.values.push_back("val2");

	company.name = "company";
	company.attributs.push_back(tel);
	company.attributs.push_back(address);

	database.push_back(person);
	database.push_back(company);

	MySQLGenerator sql_g;


	//wstring out = generate<wchar_t, data_range>(database.begin(), database.end(), sql_g);
	//wstring out = generate<wchar_t>(database.begin(), database.end(), sql_g);
	//std::wcout << out;
	
	//string out = generate<char,data_range>(database.begin(), database.end(), sql_g);
	clock_t t0 = clock();
	//string out = generate<char,data_range>(database.begin(), database.end(), sql_g);
	//wstring out = generate<wchar_t,data_range>(database.begin(), database.end(), sql_g);
	string out = generate<char,table_range,data_range>(wrap_g(database) , sql_g);
	std::cout << out;
    
	clock_t t1 = clock();
	std::cout << endl << " : " << t1-t0 << endl;

	t0 = clock();
	for(int i=0; i<database.size(); i++){
		cout << "CREATE TABLE " << database[i].name << '(';
		for (int j=0; j<database[i].attributs.size(); j++) {
			cout << database[i].attributs[j].name << ' ' << database[i].attributs[j].type;
			cout << ",\n\t\t";
		}
		cout << '\n';
	}
	
	t1 = clock();
	std::cout << endl << " : " << t1-t0 << endl;
	}
	system("pause");
}
